/*
 * @Author: hongbin
 * @Date: 2021-11-10 12:54:18
 * @LastEditors: hongbin
 * @LastEditTime: 2021-11-20 13:01:10
 * @Description:mongodb 相关请求
 */
const { MongoClient, ObjectId } = require("mongodb");
const { v1 } = require("uuid");

const dbType = {
    mongo: "mongo"
}

/**
 * @description:  当前连接的数据库的集合
 * @key {string} uuid
 * @value { client, timestamp, connectInfo } 数据库实例 上次更改的时间戳(用于清理长时间未操作的连接) 连接信息
 */
const dbObj = {};

/**
 * @description: 连接数据库
 * @param {string}  host
 * @param {string}  port
 * @param {string}  username
 * @param {string}  password
 * @param {string}  tableName
 * @return {string} uuid
 */

const createConnect_Mongo = () => (req, res) => {
    const { payload } = req;
    const { host, port, username, password, tableName } = payload;
    const url = `mongodb://${host}:${port}${tableName ? '/' + tableName : ""}`;
    const config = {
        useUnifiedTopology: true,
        auth: { username, password }
    }
    const client = new MongoClient(url, config);

    client.connect(async (err, result) => {
        if (err) {
            console.error("连接失败", err, payload);
            return res.status(400).json({ code: -1, message: "连接失败" });
        }
        console.log("连接成功");
        const id = v1();
        dbObj[id] = { client, timestamp: Date.now(), connectInfo: payload };
        // const db = await client.db().collection('blog').mapReduce();
        const db = await client.db();
        const dbs = await db.admin().listDatabases();
        console.log("dbs:", dbs);
        res.json({ code: 0, id, message: "连接成功", dbs, databaseName: db.databaseName, notification: true });
    });
}

function getClient(clientId, res, resolve) {
    const { client } = dbObj[clientId] || {};
    if (!client) return res.status(400).json({ message: '没找到该id的连接' });
    if (typeof resolve === 'function') {
        resolve(client);
    } else
        return client;
}

const getCollections = () => (req, res) => {
    console.log(req.query);
    const { type, id, databaseName } = req.query;
    if (type == dbType.mongo) {
        getClient(id, res, async (client) => {
            const collections = await client.db(databaseName).listCollections().toArray();
            console.log(databaseName + "的表:", collections);
            res.json({ code: 0, collections })
        })
    }
}

const queryCollection = () => (req, res) => {
    console.log(req.query);
    const { type, id, collection } = req.query;
    if (type == dbType.mongo) {
        getClient(id, res, async (client) => {
            const list = await client.db().collection(collection).find({}).sort({ _id: -1 }).limit(50).toArray();
            res.json({ code: 0, list });
        })
    }
}

/**
 * @description: 删除一条记录
 * @param {*} type
 * @param {*} documentId
 * @param {*} collection
 * @param {*} clientId
 */
const deleteDocument = () => async (req, res) => {
    const { type, documentId, clientId, collection } = req.payload;
    if (type === dbType.mongo) {
        getClient(clientId, res, async (client) => {
            const delItem = await client.db().collection(collection).deleteOne({ _id: ObjectId(documentId) });
            console.log("delItem:", delItem);
            if (delItem.deletedCount) {
                res.json({ code: 0, message: "删除成功", notification: true });
            }
        })
    }
}

// 转换 前端不方便处理的类型数据
const transformBSON = {
    'objectId': (val) => ObjectId(val),
    'timestamp': (val) => new Date(val).getTime(),
    'date': (val) => new Date(val),
}

/**
 * @description: 更新document
 * @param {*}  继承deleteDocument
 * @param {object}  changeField
 * @param {array<string>}  removeField
 */
const updateDocument = () => (req, res) => {
    const { type, documentId, clientId, collection, changeField, removeField } = req.payload;
    console.log("prev changeField:", changeField);
    if (type === dbType.mongo) {
        getClient(clientId, res, async (client) => {
            const updateFilter = {};
            if (removeField.length) {
                const unset = removeField.reduce((prev, curr) => {
                    prev[curr] = '';
                    return prev;
                }, {});
                updateFilter['$unset'] = unset;
            }
            // 更新字段
            const entries = Object.entries(changeField);
            if (entries.length) {
                for (let [key, value] of entries) {
                    if (Object.prototype.toString.call(value) === '[Object,Object]' && value.zxczvsv_special && value.type) {
                        changeField[key] = transformBSON[value.type](value.val);
                    }
                }
                updateFilter["$set"] = changeField;
            }
            console.log(`更新${collection}`, changeField);
            const updateItem = await client.db().collection(collection).updateOne({ _id: ObjectId(documentId) }, updateFilter, false);
            if (updateItem) {
                res.json({ code: 0, message: "更新成功", notification: true });
            }
        })
    }
}

const getAllConnect_Mongo = () => (req, res) => {
    console.log(Object.entries(dbObj));

    res.json(Object.entries(dbObj).map(([id, value]) => ({ id, ...value, client: null })));
}

module.exports = {
    createConnect_Mongo: ['post', createConnect_Mongo],
    deleteDocument: ['post', deleteDocument],
    updateDocument: ['post', updateDocument],
    getAllConnect_Mongo: ['get', getAllConnect_Mongo],
    getCollections: ['get', getCollections],
    queryCollection: ['get', queryCollection],
    // toggleDatabase: ['post', toggleDatabase]
}

/*

const toggleDatabase = () => async (req, res) => {
    const { id, databaseName, type } = req.payload;
    if (type === dbType.mongo) {
        const { client, connectInfo } = dbObj[id];
        // step 1, 断开之前的连接
        const result = await client.close();
        console.log("断开结果", result);
        // step 2, 创建新连接
        const { host, port, username, password } = connectInfo;
        const url = `mongodb://${host}:${port}/${databaseName}`;
        const config = {
            useUnifiedTopology: true,
            auth: { username, password }
        }
        const newClient = new MongoClient(url, config);

        newClient.connect(async (err, result) => {
            if (err) {
                console.error("连接失败:", err);
                return res.status(400).json({ code: -1, message: "连接失败" + err.codeName });
            }
            Object.assign(dbObj[id], { client: newClient, timestamp: Date.now() });
            res.json({ code: 0, id, message: "连接成功", databaseName, notification: true });
        });
    }
}

*/